/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/*******************************************************************************
    FILE NAME:		ecandriver.h

    PROJECT:		Linux ECAN527/1000 driver, library, and sample programs

    FILE DESCRIPTION:	This header file contains driver definitions.

    Copyright (c) 2004 RTD Embedded Technologies, Inc.

    For driver version, compiler, and target information, please refer to the
    file README.TXT.
*******************************************************************************/

#ifndef  _ECAN_DRIVER_H
# define _ECAN_DRIVER_H

# include <asm/system.h>
# include <asm/uaccess.h>
# include <decls.h>
# include <ecanbaseioctl.h>
# include <linux/fs.h>
# include <linux/init.h>
# include <linux/kernel.h> 
# include <linux/module.h>
# include <linux/poll.h>
# include <linux/version.h>


#define DRIVER_COPYRIGHT \
	"Copyright 2004 RTD Embedded Technologies, Inc.  All Rights Reserved."

#define DRIVER_DESCRIPTION "CAN bus interface board driver"

#define DRIVER_RELEASE "2.1.0"

#define DRIVER_MAJOR_VERSION 2
#define DRIVER_MINOR_VERSION 1
#define DRIVER_PATCH_LEVEL 0

#define DRIVER_MAX_BOARDS 10


/* any type I/O address */
# define   IS_IO_PROBE_AUTO(addr) (!(addr))
# define   IS_IO_PROBE_NONE(addr) ( (addr) == (__typeof__(addr)) ~0ul )

/* any type I/O address */
# define      IO_PROBE_AUTO  (                  0ul)
# define      IO_PROBE_NONE  (                 ~0ul)

# define PORT_IO_PROBE_AUTO  ( (port_io_addr_t) 0ul)
# define PORT_IO_PROBE_NONE  ( (port_io_addr_t)~0ul)

# define  MEM_IO_PROBE_AUTO  (  (mem_io_addr_t) 0ul)
# define  MEM_IO_PROBE_NONE  (  (mem_io_addr_t)~0ul)

# define     IRQ_PROBE_AUTO  (          (irq_t) 0ul)
# define     IRQ_PROBE_NONE  (          (irq_t)~0ul)

# define     DRQ_PROBE_AUTO  (          (drq_t) 0ul)
# define     DRQ_PROBE_NONE  (          (drq_t)~0ul)

# if #cpu (i386)
#  define LOW_PORT_IO_ADDR_MAX ((port_io_addr_t)0x3ff)
#  define LOW_MEM_IO_ADDR      ( (mem_io_addr_t)0xA0000)
# else	/* this #cpu unsupported yet */
#  undef  LOW_PORT_IO_ADDR_MAX
#  undef  LOW_MEM_IO_ADDR
# endif


# ifndef  __exit	/* 2.4 feature */
#  define __exit
#  define __exitdata
# endif

# ifndef  __devinit	/* CONFIG_HOTPLUG */
#  define __devinit     __init
#  define __devinitdata __initdata
#  define __devexit     __exit
#  define __devexitdata __exitdata
# endif


/* I like this names */
# define __init_text __init
# define __init_data __initdata
# define __exit_text __exit
# define __exit_data __exitdata

# define __dev_init_text __devinit
# define __dev_init_data __devinitdata
# define __dev_exit_text __devexit
# define __dev_exit_data __devexitdata


/* y is unique global name of module init function as it was before */
# ifdef module_init
#  define COMPAT_MODULE_INIT(x,y) module_init(x)
#  define COMPAT_MODULE_EXIT(x)   module_exit(x)
# else
#  ifdef MODULE
#   define COMPAT_MODULE_INIT(x,y) int     init_module(void) __attribute__((alias(#x)));
#   define COMPAT_MODULE_EXIT(x)   void cleanup_module(void) __attribute__((alias(#x)));
#  else
#   define COMPAT_MODULE_INIT(x,y) int y(void) __attribute__((alias(#x)));
#   define COMPAT_MODULE_EXIT(x)
#  endif
# endif


# undef _IOport_defined_


# ifdef __GNUC__
#  include <asm/io.h>
#
#  define OUT_PORT_8(p,v)	outb((v),(p))
#  define OUT_PORT_16(p,v)	outw((v),(p))
#  define OUT_PORT_32(p,v)	outl((v),(p))
#
#  define  IN_PORT_8(p) 	inb((p))
#  define  IN_PORT_16(p)	inw((p))
#  define  IN_PORT_32(p)	inl((p))
#
#  define _IOport_defined_
# endif

# ifndef _IOport_defined_
#  error port I/O for this OS is not considered!
# endif


typedef poll_table poll_select_table_t;


struct rtd_ecan_board;			// opaque board structure
typedef struct rtd_ecan_board board_t;


struct rtd_ecan_board_operations		// switch
{
    board_t* (*create         )(void);
    void     (*delete         )(board_t* b);


    int      (*bind           )(board_t* b, const char* name, size_t unit,
				io_addr_t tryport, irq_t tryirq, int verbose);

    void     (*unbind         )(board_t* b);


    int      (*open           )(board_t* b);
    int      (*close          )(board_t* b);


    uint     (*poll           )(board_t* b,
				struct file* f, poll_select_table_t* pst);



    size_t   (*get_board_name )(void);


    int      (*set_bus_config )(board_t* b,
				const struct __rtd_ecan_ioctl_busconfig* bcfg);

    int      (*send_command   )(board_t* b,
				const struct rtd_ecan_send_command* cmd);

    int      (*set_leds       )(board_t* b, uint led_flags);

    int      (*get_ram        )(board_t* b,
				size_t ram_offset, size_t ram_length,
				u8_t* user_buffer);

    int      (*set_ram        )(board_t* b,
				size_t ram_offset, size_t ram_length,
				const u8_t* user_buffer);


    int      (*set_rx_max_queue_size)(board_t* b, size_t max_queue_size);

    int      (*set_tx_max_queue_size)(board_t* b, size_t max_queue_size);

    int      (*clear_queues   )(board_t* b, uint queue_flags);

    int      (*get_queues_counts)(board_t* b,
				  size_t* rx_queue_count,
				  size_t* tx_queue_count);


    int      (*stop           )(board_t* b);
    int      (*start          )(board_t* b);
    int      (*test           )(board_t* b);


    int      (*prepare_received_message)(board_t* b,
					 uint* events,
					 size_t* rx_queue_count,
					 int dont_use_queue);

    int      (*get_status     )(board_t* b, struct rtd_ecan_status* status,
				int dont_use_queue);

    int      (*recv_message   )(board_t* b, struct rtd_ecan_message* msg,
				int dont_use_queue);

    int      (*send_message   )(board_t* b, const struct rtd_ecan_message* msg,
				int dont_use_queue);

    int      (*setup_message_object)(board_t* b,
				     const struct rtd_ecan_msg_obj_setup* msg,
				     int dont_use_queue);

    int      (*set_filter     )(board_t* b,
				const struct rtd_ecan_filter* filter,
				int dont_use_queue);

    int      (*set_events_mask)(board_t* b, uint events_mask);


    void     (*  get_accounts )(board_t* b, rtd_ecan_accounts_t* accounts);
    void     (*clear_accounts )(board_t* b);

    int	(*read_digital_io)(board_t *board_p, unsigned char *digital_data_p);
    int	(*write_digital_io)(board_t *board_p, unsigned char *digital_data_p);
    int	(*load_port_bit_dir)(board_t *board_p, unsigned char direction_mask);
    int	(*allow_buffer_overwrite)(board_t *board_p, unsigned char allow_flag);
};

typedef struct rtd_ecan_board_operations board_ops_t;


typedef struct
{
    struct rtd_ecan_status  status;
    struct rtd_ecan_message message;
    struct rtd_ecan_filter  filter;

    // prepare_received_message / get_interrupts fields
    size_t rx_queue_count;
    uint events;

    int set_filter;	// filter only, boolean

} __rtd_ecan_msg_t;


/*
 * These are the main single-value transfer routines.
 * "Overloaded" macros, automatically use the right size
 * if we just have the right pointer type.
 *
 * The "xxx_NOCHECK" versions of the user access functions are versions
 * that do not verify the address space.
 *
 * get_user and put_user has different "prototypes" in 2.0 and 2.1 kernels.
 *
 * err  GET_USER(x,addr);
 * err  PUT_USER(x,addr);
 * void GET_USER_NOCHECK(x,addr);
 * void PUT_USER_NOCHECK(x,addr);
 *
 * get_user and put_user returns 0 for success and -EFAULT for bad access.
 */


/*
 * Copy from/to userspace
 *
 * COPY_FROM_USER and COPY_TO_USER returns the number of bytes they failed
 * to copy (so zero is a successful return).
 */

# define GET_USER(x,addr) get_user(x,addr)
# define PUT_USER(x,addr) put_user(x,addr)
# define GET_USER_NOCHECK(x,addr) __get_user(x,addr)
# define PUT_USER_NOCHECK(x,addr) __put_user(x,addr)
#
# define COPY_FROM_USER(kdst,usrc,len) copy_from_user(kdst,usrc,len)
# define COPY_TO_USER(udst,ksrc,len)   copy_to_user(udst,ksrc,len)
# define COPY_FROM_USER_NOCHECK(kdst,usrc,len) __copy_from_user(kdst,usrc,len)
# define COPY_TO_USER_NOCHECK(udst,ksrc,len)   __copy_to_user(udst,ksrc,len)


# define FILE_OPERATIONS_CLOSE_TYPE int
# define FILE_OPERATIONS_CLOSE_VALUE(rc) (rc)


# define FILE_OPERATIONS_SEEK_PROTOTYPE(name,_inode,_file,_offset,_origin) \
    loff_t name (struct file* _file, loff_t _offset, int _origin)


# define FILE_OPERATIONS_READ_PROTOTYPE(name,_inode,_file,_buf,_len,_offset) \
    ssize_t name (struct file* _file, char* _buf, size_t _len, loff_t* _offset)


# define FILE_OPERATIONS_WRITE_PROTOTYPE(name,_inode,_file,_buf,_len,_offset) \
    ssize_t name (struct file* _file, const char* _buf, size_t _len, loff_t* _offset)


# if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) /* 2.4.0..3 */

#  define COMPAT_FILE_OPERATIONS_INIT( \
	seek,read,write,readdir,       \
	select,poll,                   \
	ioctl,mmap,open,               \
	flush,                         \
	release,fsync,fasync,          \
	check_media_change,revalidate, \
	lock,                          \
	readv,writev,                  \
	sendpage,get_unmapped_area)    \
\
	{\
		THIS_MODULE, \
		seek,read,write,readdir, poll, ioctl,mmap,open, \
		flush, release,fsync,fasync, \
		lock, \
		readv,writev \
	}

# else	/* 2.4.4+ */

#  define COMPAT_FILE_OPERATIONS_INIT( \
	seek,read,write,readdir,       \
	select,poll,                   \
	ioctl,mmap,open,               \
	flush,                         \
	release,fsync,fasync,          \
	check_media_change,revalidate, \
	lock,                          \
	readv,writev,                  \
	sendpage,get_unmapped_area)    \
\
	{\
		THIS_MODULE, \
		seek,read,write,readdir, poll, ioctl,mmap,open, \
		flush, release,fsync,fasync, \
		lock, \
		readv,writev, \
		sendpage,get_unmapped_area \
	}

# endif


# define COMPAT_INODE_OPERATIONS_INIT( \
	default_file_ops,                \
	create, lookup,                  \
	link, unlink, symlink,           \
	mkdir, rmdir, mknod, rename,     \
	readlink, follow_link,           \
	readpage, writepage,             \
	bmap, truncate, permission, smap \
	,updatepage, revalidate          \
	,prepare_write, sync_page)       \
\
	{\
		default_file_ops,                \
		create, lookup,                  \
		link, unlink, symlink,           \
		mkdir, rmdir, mknod, rename,     \
		readlink, follow_link,           \
		readpage, writepage,             \
		bmap, truncate, permission, smap \
		,updatepage, revalidate          \
		,prepare_write, sync_page        \
	}

 
# define FILE_INODE(file) ((file)->f_dentry->d_inode)


# define INODE_MINOR(inode) ((unsigned int)MINOR((inode)->i_rdev))
# define INODE_MAJOR(inode) ((unsigned int)MAJOR((inode)->i_rdev))

# define FILE_MINOR(file) (INODE_MINOR(FILE_INODE(file)))
# define FILE_MAJOR(file) (INODE_MAJOR(FILE_INODE(file)))


# define FILE_OWNER_PID(file) ((file)->f_owner.pid)


# define EXPORT_SYMBOL_END ;
# define register_symtab(symtab)
# undef  COMPAT_REGISTER_SYMTAB_NEEDED


# if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
#  define MODULE_LICENSE(license)
# endif


# define COMPAT_MOD_INC_USE_COUNT
# define COMPAT_MOD_DEC_USE_COUNT


# ifdef NDEBUG

#  define assert(expr)            ((void) 0)
#  define assert_retvoid(expr)    ((void) 0)
#  define assert_retval(expr,val) ((void) 0)
#  define assert_goto(expr,label) ((void) 0)
#  define assert_break(expr)      ((void) 0)

# else	/* ndef NDEBUG */

#  define __assertion_failed(expr) \
	( printk(KERN_ERR "%s:%u: %s: Assertion `%s' failed.\n", \
		__FILE__, __LINE__, __PRETTY_FUNCTION__, #expr) )

#  define __assert(expr) \
	( (expr) ? 1 : (__assertion_failed(expr), 0) )

#  define assert(expr) ((void) __assert(expr))

#  define assert_retvoid(expr) \
	do { if (!__assert(expr)) return; } while(0)

#  define assert_retval(expr,val) \
	do { if (!__assert(expr)) return (val); } while(0)

#  define assert_goto(expr,label) \
	do { if (!__assert(expr)) goto label; } while(0)

#  define assert_break(expr) \
	if (!__assert(expr)) break

# endif	/* def NDEBUG */


# define PRINTF(fmt, args...)   printk(fmt , ##args)

# define PRINT_ENDL() PRINTF("\n")


# define PRINT_FILE_LINE()	\
	PRINTF(__FILE__ ":%4u: ", __LINE__)

# define PRINT_SHORTFILE_LINE()	PRINT_FILE_LINE()

# define PRINT_FILE_LINE_FUNCTION()	\
	PRINTF(__FILE__ ":%4u: %s()", __LINE__, __FUNCTION__)

# define PRINT_SHORTFILE_LINE_FUNCTION()	PRINT_FILE_LINE_FUNCTION()

# define PRINT_FILE_LINE_PRETTY_FUNCTION()	\
	PRINTF(__FILE__ ":%4u: %s", __LINE__, __PRETTY_FUNCTION__)

# define PRINT_SHORTFILE_LINE_PRETTY_FUNCTION()	\
	PRINT_FILE_LINE_PRETTY_FUNCTION()


__C_DECL void print_trace_count(void);


# define TRACE()	\
	( print_trace_count(), PRINT_SHORTFILE_LINE_FUNCTION(), PRINT_ENDL() )

# define TRACEF(fmt, args...)	\
	( print_trace_count(), PRINT_SHORTFILE_LINE_FUNCTION(), \
		PRINTF(": " fmt , ##args) )

# define LTRACE()	\
	( print_trace_count(), PRINT_SHORTFILE_LINE_PRETTY_FUNCTION(), \
		PRINT_ENDL() )

# define LTRACEF(fmt, args...)	\
	( print_trace_count(), PRINT_SHORTFILE_LINE_PRETTY_FUNCTION(), \
		PRINTF(": " fmt , ##args) )


#endif	/* _ECAN_DRIVER_H */
